package org.jpropeller.problem.impl;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Dimension;

import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.SpinnerNumberModel;
import javax.swing.table.TableCellRenderer;

import org.jpropeller.info.PropEditability;
import org.jpropeller.ui.impl.IconAndHTMLCellRenderer;
import org.jpropeller.view.problem.impl.ProblemRenderer;

/**
 * A TableCellRenderer for Problems.
 * If the Problem is an IgnorableProblem, an "ignore this" checkbox is displayed.
 */
public class ProblemCellRenderer extends JPanel implements TableCellRenderer
{
	private final IconAndHTMLCellRenderer delegate;
	private final JLabel leftIconLabel;
	private final JLabel textLabel1;
	private final JLabel textLabel2;
	private final JLabel textLabel3;
	private final JCheckBox checkbox;
	private final JSpinner spinner;
	
	private final JLabel spinnerText;
	private JPanel spinnerPanel;
	
	private final boolean adjustRowHeight=true;
	
	public JCheckBox getCheckBox()
	{
		return checkbox;
	}
	
	public JSpinner getSpinner()
	{
		return spinner;
	}
	
	private JPanel panel1;	
	private JPanel panel2;
	private JPanel panel3;
	
	private JPanel cards;
	
	private CardLayout cl;

	private final String NONE="none";
	private final String CHECKBOX="checkbox";
	private final String SPINNER="spinner";
	
	private String currentCard;
	
	public Object getValue()
	{
		if(currentCard.equals(CHECKBOX))
		{
			return getCheckBox().isSelected();
		}
		if(currentCard.equals(SPINNER))
		{
			return getSpinner().getValue();
		}
		return null;
	}
	
	public ProblemCellRenderer()
	{
		this(new IconAndHTMLCellRenderer(ProblemRenderer.get()));
	}
	
	public ProblemCellRenderer(IconAndHTMLCellRenderer delegate)
	{
		super(new BorderLayout(10,10));
		this.delegate=delegate;
		add(leftIconLabel=new JLabel(),BorderLayout.WEST);
		
		spinnerText=new JLabel();

		panel1=new JPanel(new BorderLayout());
		panel1.add(textLabel1=new JLabel(),BorderLayout.CENTER);
		panel1.add(checkbox=new JCheckBox("Ignore this."),BorderLayout.SOUTH);

		panel3=new JPanel(new BorderLayout());
		panel3.add(textLabel3=new JLabel(),BorderLayout.CENTER);
		spinnerPanel=new JPanel(new BorderLayout(5,0));
		spinnerPanel.add(spinnerText,BorderLayout.WEST);
		spinnerPanel.add(spinner=new JSpinner(),BorderLayout.CENTER);
		panel3.add(spinnerPanel,BorderLayout.SOUTH);

		panel2=new JPanel(new BorderLayout());
		panel2.add(textLabel2=new JLabel(),BorderLayout.CENTER);

		textLabel1.setVerticalAlignment(JLabel.TOP);
		textLabel1.setVerticalTextPosition(JLabel.TOP);
		textLabel2.setVerticalAlignment(JLabel.TOP);
		textLabel2.setVerticalTextPosition(JLabel.TOP);
		textLabel3.setVerticalAlignment(JLabel.TOP);
		textLabel3.setVerticalTextPosition(JLabel.TOP);
		
		cards = new JPanel(cl=new CardLayout());
		cards.add(panel1, CHECKBOX);
		cards.add(panel2, NONE);
		cards.add(panel3, SPINNER);

		add(cards,BorderLayout.CENTER);
		
		
	}

	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		JLabel l=(JLabel)delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
		//setOpaque(l.isOpaque());
		setBorder(l.getBorder());
		setBackground(l.getBackground());
		setForeground(l.getForeground());
		panel1.setBackground(l.getBackground());
		panel2.setBackground(l.getBackground());
		panel3.setBackground(l.getBackground());
		spinnerPanel.setBackground(l.getBackground());
		panel1.setForeground(l.getForeground());
		panel2.setForeground(l.getForeground());
		panel3.setForeground(l.getForeground());
		spinnerPanel.setForeground(l.getForeground());
		
		leftIconLabel.setIcon(l.getIcon());
		
		textLabel1.setText(l.getText());
		textLabel2.setText(l.getText());
		textLabel3.setText(l.getText());

		textLabel1.setForeground(l.getForeground());
		textLabel2.setForeground(l.getForeground());
		textLabel3.setForeground(l.getForeground());
		spinnerText.setForeground(l.getForeground());
		
		if(value instanceof IgnorableProblem)
		{
			checkbox.setSelected(((IgnorableProblem)value).ignore().get());
			checkbox.setForeground(l.getForeground());
			checkbox.setEnabled(((IgnorableProblem)value).ignore().getEditability()==PropEditability.EDITABLE);
			checkbox.setText(((IgnorableProblem)value).ignoreText().get());
			currentCard=CHECKBOX;
		}
		else if(value instanceof NumberProblem)
		{
			Number number=((NumberProblem)value).number().get();
			Number numberMin=((NumberProblem)value).numberMin().get();
			Number numberMax=((NumberProblem)value).numberMax().get();
			if(number instanceof Integer)
			{
				spinner.setModel(new SpinnerNumberModel(((Integer)number).intValue(),((Integer)numberMin).intValue(),((Integer)numberMax).intValue(),1));
			}
			else if(number instanceof Double)
			{
				spinner.setModel(new SpinnerNumberModel(((Double)number).doubleValue(),((Double)numberMin).doubleValue(),((Double)numberMax).doubleValue(),0.1));
			}
			else
			{
				spinner.setValue(((NumberProblem)value).number().get());
			}
			spinner.setEnabled(((NumberProblem)value).number().getEditability()==PropEditability.EDITABLE);
			spinnerText.setText(((NumberProblem)value).numberText().get());
			spinner.getEditor().setForeground(l.getForeground());
			spinner.getEditor().setBackground(l.getBackground());
			currentCard=SPINNER;
		}
		else
		{
			currentCard=NONE;
		}
		cl.show(cards, currentCard);
		
		
		if(adjustRowHeight)
		{
			if(column<table.getColumnCount() && row<table.getRowCount())
			{
				int width=table.getColumnModel().getColumn(column).getWidth();
				int availableWidth = width-(l.getIcon().getIconWidth()+10);
				if(l.getText().startsWith("<html>"))
				{
					Dimension d=getPreferredSize(textLabel1,true, availableWidth);
					int height=d.height+textLabel1.getInsets().top+textLabel1.getInsets().bottom+getInsets().top+getInsets().bottom;
					if(currentCard.equals(CHECKBOX))
					{
						height+=checkbox.getPreferredSize().height+10;
					}
					if(currentCard.equals(SPINNER))
					{
						height+=spinner.getPreferredSize().height+10;
					}
					table.setRowHeight(row, Math.max(height, l.getIcon().getIconHeight()+getInsets().top+getInsets().bottom));
				}
			}
		}
		
		
		return this;
	}
	
    /**
     * Returns the preferred size to set a component at in order to render
     * an html string.  You can specify the size of one dimension.
     * see http://blog.nobel-joergensen.com/2009/01/18/changing-preferred-size-of-a-html-jlabel/
     * */
    private static Dimension getPreferredSize(JLabel resizer,boolean width, int prefSize) {
 
        javax.swing.text.View view = (javax.swing.text.View) resizer.getClientProperty(
                javax.swing.plaf.basic.BasicHTML.propertyKey);
        
        if(view==null)
        {
        	return new Dimension(0,0);
        }
 
        view.setSize(width?prefSize:0,width?0:prefSize);
 
        float w = view.getPreferredSpan(javax.swing.text.View.X_AXIS);
        float h = view.getPreferredSpan(javax.swing.text.View.Y_AXIS);
 
        return new Dimension((int) Math.ceil(w),
                (int) Math.ceil(h));
    }
	
}
